<?php

/**
 * Task for creating project
 *
 * @author Andrey Kucherenko (kucherenko.andrey@gmail.com)
 * @version 0.3
 * @task create
 */
class CompleXml_Cli_Task_Create extends CompleXml_Cli_Task
{

    private $_settings = array();
    
    public function  __construct($argv)
    {
        $options = array(
            '--full'=>array(
                'aliases'=>array('-f'),
            ),
            '--name'=>array(
                'position'=>3,
                'type'=>'String'
            ),
            '--with-lib'=>array(),
            '--dir'=>array(
                'type'=>'Dir',
                'aliases'=>array('-d')
            ),
            '--like'=>array(
                'type'=>'String'
            )
        );
        parent::__construct($argv, $options);
    }
    
    public function init()
    {
        $this->_settings = CompleXml_Config::readComponentSettings(__CLASS__);
    }

    /**
     * Create project, use --dir option for show destination directory
     * default working directory is a current directory
     * use --with-lib for coping CompleXml Framework to lib directory of project
     *
     * @throws CompleXml_Cli_Exception
     * @example create project name --dir /opt/workspace
     * @example create project --name=projectname
     * @example create project --name projectname
     * @action project
     */
    public function project()
    {
        $name = $this->Getopt->getValue('--name');
        if (is_null($name)) {
            throw new CompleXml_Cli_Exception('Enter name of project');
        }
        $dir = $this->Getopt->getValue('-d');
        if (!is_null($dir) && file_exists($dir)) {
            $project_directory = $dir . DIRECTORY_SEPARATOR . $name;
        } else {
            if (!is_null($dir)) {
                throw new CompleXml_Cli_Exception('Directory ' . $dir . ' not exists');
            }
            $project_directory = APPLICATION_HOME . DIRECTORY_SEPARATOR . $name;
        }
        if (file_exists($project_directory) && is_dir($project_directory)) {
            throw new CompleXml_Cli_Exception('Folder "' . $project_directory . '" already exists');
        }
        if (!mkdir($project_directory, 0755)) {
            throw new CompleXml_Cli_Exception('Can\'t create folder named "' . $name . '"');
        }
        CompleXml_Log::info('>Created ' . $project_directory . ' for application');
        $this->_copy($this->_settings['sandbox'], $project_directory);
        CompleXml_Log::info('>Sandbox copied to "' . $project_directory . '"');
        mkdir($project_directory . DIRECTORY_SEPARATOR . 'logs', 0777);
        mkdir($project_directory . DIRECTORY_SEPARATOR . 'cache', 0777);
        chmod($project_directory . DIRECTORY_SEPARATOR . 'cx', 0777);
        chmod($project_directory . DIRECTORY_SEPARATOR . 'logs', 0777);
        chmod($project_directory . DIRECTORY_SEPARATOR . 'cache', 0777);
        if ($this->Getopt->getValue('--with-lib')) {
            $this->_copy(CompleXml_Loader::getLibraryPath() . DIRECTORY_SEPARATOR . 'CompleXml', $project_directory . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'CompleXml');
            CompleXml_Log::info('>CompleXml framework copied to "' . $project_directory . DIRECTORY_SEPARATOR . 'lib"');
            $this->_copy(CompleXml_Loader::getLibraryPath() . DIRECTORY_SEPARATOR . 'CompleXmlData', $project_directory . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'CompleXmlData');
            CompleXml_Log::info('>CompleXmlData copied to "' . $project_directory . DIRECTORY_SEPARATOR . 'lib"');
        }
        CompleXml_Log::notice('Project created');
        CompleXml_Log::notice('For manage project, use "' . $project_directory . DIRECTORY_SEPARATOR . 'cx" script');
    }

    /**
     * Create controller, use --like option for show example controller
     *
     * @throws CompleXml_Cli_Exception
     * @example create controller controllername
     * @example create controller testcontroller --like controllername
     * @action controller
     */
    public function controller()
    {
        $parent = 'CompleXml_Controller';
        $actions =
<<<_ACTIONS
/**
    * Index action generated by CompleXml Framework version 0.3
    */
    public function indexAction()
    {
    }
_ACTIONS;

        $dir = $this->Getopt->getValue('--dir');
        $like = $this->Getopt->getValue('--like');
        $name = $this->Getopt->getValue('--name');

        if (is_null($name)) {
            throw new CompleXml_Cli_Exception('Enter controller name');
        }
        $view_path = $name;
        $name = strtolower($name) . 'Controller';

        if (!is_null($dir) && file_exists($dir)) {
            $controllers_directory = $dir;
        } else {
            if (!is_null($dir)) {
                CompleXml_Log::err('Directory ' . $dir . ' not exists');
            }
            $controllers_directory = CompleXml_Config::getSettings('Application', 'controllers');
        }

        if (file_exists($controllers_directory . DIRECTORY_SEPARATOR . $name . '.php')) {
            throw new CompleXml_Cli_Exception('Controller already exists');
        }

        if (!is_null($like)) {
            if (file_exists($controllers_directory . DIRECTORY_SEPARATOR . $like . 'Controller.php')) {
                include_once $controllers_directory . DIRECTORY_SEPARATOR . $like . 'Controller.php';
                CompleXml_Log::info('>Controller ' . $like . 'Controller.php use as template for current controller');
                $ref = new ReflectionClass($like . 'Controller');

                $parent = $ref->getParentClass()->getName();

                $methods = $ref->getMethods(ReflectionMethod::IS_PUBLIC);

                $res = '';
                foreach ($methods as $method) {
                    if ($method->getDeclaringClass()->getName()==$ref->getName()){
                        $res .= "\n    ".$method->getDocComment();
                        $res .= "\n    public function " . $method->getName() . "()\n";
                        $res .= "    {\n";
                        $res .= "    }\n";
                        CompleXml_Log::info('>Added method '.$method->getName(). ' from ' . $like . 'Controller to current controller');
                    }
                }
                $actions = $res;
                
            }
        }

        $template = file_get_contents(CompleXml_Config::getSettings(__CLASS__, 'controller'));
        $result = str_replace('[?php', '<?php', $template);
        $result = str_replace('{date}', date('c'), $result);
        $result = str_replace('{ParentController}', $parent, $result);
        CompleXml_Log::info('>'.$parent.' used as parent of current controller');
        $result = str_replace('{controllerName}', $name, $result);
        $result = str_replace('{actions}', $actions, $result);

        $is_created = file_put_contents($controllers_directory . DIRECTORY_SEPARATOR . $name . '.php', $result);
        if (!$is_created){
            throw new CompleXml_Cli_Exception('Can\'t write to file '.$controllers_directory . DIRECTORY_SEPARATOR . $name . '.php');
        }else{
            CompleXml_Log::notice('>Controller '.$name.' created');
        }
    }
    
    private function _copy($source, $dest, $folderPermission = 0755, $filePermission = 0644)
    {
        $result = false;
        $current_umask = umask();
        umask(0000);
        if (is_file($source)) {
            if (is_dir($dest)) {
                if ($dest[strlen($dest) - 1] != DIRECTORY_SEPARATOR)
                    $__dest = $dest . DIRECTORY_SEPARATOR;
                $__dest .= basename($source);
            }
            else {
                $__dest = $dest;
            }
            $result = copy($source, $__dest);
            chmod($__dest, $filePermission);
        }
        elseif(is_dir($source)) {
            if (!is_dir($dest)) {
                @mkdir($dest, $folderPermission);
                chmod($dest, $folderPermission);
            }
            if ($source[strlen($source) - 1] != DIRECTORY_SEPARATOR)
                $source = $source . DIRECTORY_SEPARATOR;
            if ($dest[strlen($dest) - 1] != DIRECTORY_SEPARATOR)
                $dest = $dest . DIRECTORY_SEPARATOR;

            $return = true;
            $dirHandle = opendir($source);
            while ($file = readdir($dirHandle)) {
                if ($file != "." && $file != "..") {
                    $result = $this->_copy($source . $file, $dest . $file, $folderPermission, $filePermission);
                }
            }
            closedir($dirHandle);
        }
        else {
            $result = false;
        }
        umask($current_umask);
        return $result;
    }
}


